﻿// <copyright file="TrackSmoothStreamingMediaElement.cs" company="Microsoft Corporation">
// Copyright (c) 2009 Microsoft Corporation All Rights Reserved
// </copyright>
// <author>Michael S. Scherotter</author>
// <email>mischero@microsoft.com</email>
// <date>2009-09-03</date>
// <summary>TrackSmoothStreamingMediaElement class definition</summary>

namespace Microsoft.WebAnalytics.Media
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel.Composition;
    using System.Linq;
    using System.Windows;
    using System.Windows.Interactivity;
    using System.Windows.Media;
    using Microsoft.Web.Media.SmoothStreaming;
    using Microsoft.WebAnalytics;
    using Microsoft.WebAnalytics.Data;

    /// <summary>
    /// <img src="../media/Microsoft.WebAnalytics.Media.TrackSmoothStreamingMediaElement.24x24.png"/> 
    /// Smooth Streaming Media Element event tracking (Silverlight 4 only)
    /// </summary>
    /// <example>
    /// Adding this behavior via code:
    /// <code>
    /// var ssme = new SmoothStreamingMediaElement();
    /// var behaviors = System.Windows.Interactivity.Interaction.GetBehaviors(ssme);
    /// behaviors.Add(new TrackSmoothStreamingMediaElement());
    /// </code>
    /// </example>
    public class TrackSmoothStreamingMediaElement : Behavior<SmoothStreamingMediaElement>
    {
        /// <summary>
        /// Initializes a new instance of the TrackSmoothStreamingMediaElement class
        /// </summary>
        public TrackSmoothStreamingMediaElement()
        {
            this.CustomProperties = new Collection<PropertyValue>();
        }

        #region Properties
        /// <summary>
        /// Gets custom properties (name/value pairs) for the action
        /// </summary>
        public Collection<PropertyValue> CustomProperties { get; private set; }

        /// <summary>
        /// Gets or sets the event Logging method
        /// </summary>
        [Import("Log")]
        public Action<AnalyticsEvent> Log { get; set; }

        /// <summary>
        /// Gets the Media Source or Smooth Streaming Source
        /// </summary>
        private Uri Source
        {
            get
            {
                if (this.AssociatedObject.SmoothStreamingSource == null)
                {
                    return this.AssociatedObject.Source;
                }

                return this.AssociatedObject.SmoothStreamingSource;
            }
        }
        #endregion

        #region Methods
        /// <summary>
        /// Initialize the imports and attach the event handlers
        /// </summary>
        protected override void OnAttached()
        {
            base.OnAttached();

#if WP7S
            CompositionInitializer.SatisfyImports(this);
#else
            PartInitializer.SatisfyImports(this);
#endif

            this.AssociatedObject.BufferingProgressChanged += new RoutedEventHandler(this.BufferingProgressChanged);
            this.AssociatedObject.ClipClickThrough += new EventHandler<ClipEventArgs>(this.ClipClickThrough);
            this.AssociatedObject.ClipError += new EventHandler<ClipEventArgs>(this.ClipError);
            this.AssociatedObject.ClipStateChanged += new RoutedEventHandler(this.ClipStateChanged);
            this.AssociatedObject.CurrentStateChanged += new RoutedEventHandler(this.CurrentStateChanged);
            this.AssociatedObject.DownloadTrackChanged += new EventHandler<TrackChangedEventArgs>(this.DownloadTrackChanged);
            this.AssociatedObject.DurationExtended += new EventHandler<DurationExtendedEventArgs>(this.DurationExtended);
            this.AssociatedObject.LiveEventCompleted += new EventHandler(this.LiveEventCompleted);
            this.AssociatedObject.LogReady += new LogReadyRoutedEventHandler(this.LogReady);
            this.AssociatedObject.MarkerReached += new TimelineMarkerRoutedEventHandler(this.MarkerReached);
            this.AssociatedObject.MediaEnded += new RoutedEventHandler(this.MediaEnded);
            this.AssociatedObject.MediaFailed += new EventHandler<ExceptionRoutedEventArgs>(this.MediaFailed);
            this.AssociatedObject.MediaOpened += new RoutedEventHandler(this.MediaOpened);
            this.AssociatedObject.PlaybackTrackChanged += new EventHandler<TrackChangedEventArgs>(this.PlaybackTrackChanged);
            this.AssociatedObject.SeekCompleted += new EventHandler<SeekCompletedEventArgs>(this.SeekCompleted);
            this.AssociatedObject.SmoothStreamingErrorOccurred += new EventHandler<SmoothStreamingErrorEventArgs>(this.SmoothStreamingErrorOccurred);
            this.AssociatedObject.TimelineEventReached += new EventHandler<TimelineEventArgs>(this.TimelineEventReached);
        }

        /// <summary>
        /// Detach the event handlers
        /// </summary>
        protected override void OnDetaching()
        {
            base.OnDetaching();

            this.AssociatedObject.BufferingProgressChanged -= new RoutedEventHandler(this.BufferingProgressChanged);
            this.AssociatedObject.ClipClickThrough -= new EventHandler<ClipEventArgs>(this.ClipClickThrough);
            this.AssociatedObject.ClipError -= new EventHandler<ClipEventArgs>(this.ClipError);
            this.AssociatedObject.ClipStateChanged -= new RoutedEventHandler(this.ClipStateChanged);
            this.AssociatedObject.CurrentStateChanged -= new RoutedEventHandler(this.CurrentStateChanged);
            this.AssociatedObject.DownloadTrackChanged -= new EventHandler<TrackChangedEventArgs>(this.DownloadTrackChanged);
            this.AssociatedObject.DurationExtended -= new EventHandler<DurationExtendedEventArgs>(this.DurationExtended);
            this.AssociatedObject.LiveEventCompleted -= new EventHandler(this.LiveEventCompleted);
            this.AssociatedObject.LogReady -= new LogReadyRoutedEventHandler(this.LogReady);
            this.AssociatedObject.MarkerReached -= new TimelineMarkerRoutedEventHandler(this.MarkerReached);
            this.AssociatedObject.MediaEnded -= new RoutedEventHandler(this.MediaEnded);
            this.AssociatedObject.MediaFailed -= new EventHandler<ExceptionRoutedEventArgs>(this.MediaFailed);
            this.AssociatedObject.MediaOpened -= new RoutedEventHandler(this.MediaOpened);
            this.AssociatedObject.PlaybackTrackChanged -= new EventHandler<TrackChangedEventArgs>(this.PlaybackTrackChanged);
            this.AssociatedObject.SeekCompleted -= new EventHandler<SeekCompletedEventArgs>(this.SeekCompleted);
            this.AssociatedObject.SmoothStreamingErrorOccurred -= new EventHandler<SmoothStreamingErrorEventArgs>(this.SmoothStreamingErrorOccurred);
            this.AssociatedObject.TimelineEventReached -= new EventHandler<TimelineEventArgs>(this.TimelineEventReached);
        }

        #endregion

        #region Implementation

        /// <summary>
        /// Log a TimelineEventReached event
        /// </summary>
        /// <param name="sender">the SSME object</param>
        /// <param name="e">the timeline event arguments</param>
        private void TimelineEventReached(object sender, TimelineEventArgs e)
        {
            var logEvent = new AnalyticsEvent()
            {
                EventArgs = this.CustomProperties,
                Name = "TimelineEventReached",
                ObjectName = this.AssociatedObject.Name,
                ObjectType = this.AssociatedObject.GetType().Name,
                MediaSource = this.Source,
                MediaTimeCode = this.AssociatedObject.Position,
                Track = new Microsoft.WebAnalytics.Data.TrackInfo()
                {
                    Bitrate = System.Convert.ToInt64(e.Track.Bitrate),
                    CustomAttributes = new Dictionary<string, string>(e.Track.CustomAttributes),
                    Index = e.Track.Index,
                    Language = e.Track.Language,
                    Name = e.Track.Name,
                    TrackData = new List<Microsoft.WebAnalytics.Data.TimelineEvent>(from timelineEvent in e.Track.TrackData
                                                                                    select new Microsoft.WebAnalytics.Data.TimelineEvent
                                                                                    {
                                                                                        EventTime = timelineEvent.EventTime
                                                                                    }),
                },
                Value = System.Convert.ToInt32(e.IsCurrent),   
            };

            this.Log(logEvent);
        }

        /// <summary>
        /// Log a SmoothStreamingErrorOccurred event
        /// </summary>
        /// <param name="sender">the SmoothStreamingMediaElement</param>
        /// <param name="e">the smooth streaming error event argumetns</param>
        private void SmoothStreamingErrorOccurred(object sender, SmoothStreamingErrorEventArgs e)
        {
            var logEvent = new AnalyticsEvent()
            {
                ActionValue = e.ErrorMessage,
                EventArgs = this.CustomProperties,
                Name = "SmoothStreamingErrorOccurred",
                ObjectName = this.AssociatedObject.Name,
                ObjectType = this.AssociatedObject.GetType().Name,
                MediaSource = this.Source,
                MediaTimeCode = this.AssociatedObject.Position,
                Value = e.ErrorCode
            };

            this.Log(logEvent);
        }

        /// <summary>
        /// Log the SeekCompleted event
        /// </summary>
        /// <param name="sender">the SmoothStreamingMediaElement</param>
        /// <param name="e">the seek completed event arguments</param>
        private void SeekCompleted(object sender, SeekCompletedEventArgs e)
        {
            var logEvent = new AnalyticsEvent()
            {
                EventArgs = this.CustomProperties,
                Name = "SeekCompleted",
                ObjectName = this.AssociatedObject.Name,
                ObjectType = this.AssociatedObject.GetType().Name,
                MediaSource = this.Source,
                MediaTimeCode = e.ActualSeekPosition,
                Value = System.Convert.ToInt32(e.Success),   
            };

            this.Log(logEvent);
        }

        /// <summary>
        /// Log the PlaybackTrackChanged event
        /// </summary>
        /// <param name="sender">the SmoothStreamingMediaElement</param>
        /// <param name="e">the track changed event arguments</param>
        private void PlaybackTrackChanged(object sender, TrackChangedEventArgs e)
        {
            var logEvent = new AnalyticsEvent()
            {
                EventArgs = this.CustomProperties,
                Name = "PlaybackTrackChanged",
                ObjectName = this.AssociatedObject.Name,
                ObjectType = this.AssociatedObject.GetType().Name,
                MediaSource = this.Source,
                MediaTimeCode = this.AssociatedObject.Position,
                Track = new Microsoft.WebAnalytics.Data.TrackInfo()
                {
                    Bitrate = System.Convert.ToInt64(e.Track.Bitrate),
                    CustomAttributes = new Dictionary<string, string>(e.Track.CustomAttributes),
                    Index = e.Track.Index,
                    Language = e.Track.Language,
                    Name = e.Track.Name,
                    TrackData = new List<Microsoft.WebAnalytics.Data.TimelineEvent>(from timelineEvent in e.Track.TrackData
                                                                                    select new Microsoft.WebAnalytics.Data.TimelineEvent
                                                                                    {
                                                                                        EventTime = timelineEvent.EventTime
                                                                                    }),
                },
            };

            this.Log(logEvent);
        }

        /// <summary>
        /// Log the MediaOpened Event
        /// </summary>
        /// <param name="sender">the SmoothStreamingMediaElement</param>
        /// <param name="e">the routed event arguments</param>
        private void MediaOpened(object sender, RoutedEventArgs e)
        {
            var logEvent = new AnalyticsEvent()
            {
                EventArgs = this.CustomProperties,
                Name = "MediaOpened",
                ObjectName = this.AssociatedObject.Name,
                ObjectType = this.AssociatedObject.GetType().Name,
                MediaSource = this.Source,
                MediaTimeCode = this.AssociatedObject.Position,
            };

            this.Log(logEvent);
        }

        /// <summary>
        /// Log the MediaFailed event
        /// </summary>
        /// <param name="sender">the SmoothStreamingMediaElement</param>
        /// <param name="e">the exception routed event arguments</param>
        private void MediaFailed(object sender, ExceptionRoutedEventArgs e)
        {
            var logEvent = new AnalyticsEvent()
            {
                ActionValue = e.ErrorException.Message,
                EventArgs = this.CustomProperties,
                Name = "MediaFailed",
                ObjectName = this.AssociatedObject.Name,
                ObjectType = this.AssociatedObject.GetType().Name,
                MediaSource = this.Source,
                MediaTimeCode = this.AssociatedObject.Position,
            };

            this.Log(logEvent);
        }

        /// <summary>
        /// Log the MediaEnded event
        /// </summary>
        /// <param name="sender">the SmoothStreamingMediaElement</param>
        /// <param name="e">the routed event arguments</param>
        private void MediaEnded(object sender, RoutedEventArgs e)
        {
            var logEvent = new AnalyticsEvent()
            {
                EventArgs = this.CustomProperties,
                Name = "MediaEnded",
                ObjectName = this.AssociatedObject.Name,
                ObjectType = this.AssociatedObject.GetType().Name,
                MediaSource = this.Source,
                MediaTimeCode = this.AssociatedObject.Position,
            };

            this.Log(logEvent);
        }

        /// <summary>
        /// Log the MarkerReached event
        /// </summary>
        /// <param name="sender">the SmoothStreamingMediaElement</param>
        /// <param name="e">the timeline marker routed event arguments</param>
        private void MarkerReached(object sender, TimelineMarkerRoutedEventArgs e)
        {
            var logEvent = new AnalyticsEvent()
            {
                ActionValue = e.Marker.Text,
                EventArgs = this.CustomProperties,
                Name = "MarkerReached",
                ObjectName = this.AssociatedObject.Name,
                ObjectType = this.AssociatedObject.GetType().Name,
                MediaSource = this.Source,
                MediaTimeCode = this.AssociatedObject.Position,
            };

            this.Log(logEvent);
        }

        /// <summary>
        /// Log the LogReady event
        /// </summary>
        /// <param name="sender">the SmoothStreamingMediaElement</param>
        /// <param name="e">the log ready routed event arguments</param>
        private void LogReady(object sender, LogReadyRoutedEventArgs e)
        {
            var logEvent = new AnalyticsEvent()
            {
                ActionValue = e.Log,
                EventArgs = this.CustomProperties,
                Name = "LogReady",
                ObjectName = this.AssociatedObject.Name,
                ObjectType = this.AssociatedObject.GetType().Name,
                MediaSource = this.Source,
                MediaTimeCode = this.AssociatedObject.Position,
            };

            this.Log(logEvent);
        }

        /// <summary>
        /// Log the LiveEventCompleted event
        /// </summary>
        /// <param name="sender">the SmoothStreamingMediaElement</param>
        /// <param name="e">the event arguments</param>
        private void LiveEventCompleted(object sender, EventArgs e)
        {
            var logEvent = new AnalyticsEvent()
            {
                EventArgs = this.CustomProperties,
                Name = "LiveEventCompleted",
                ObjectName = this.AssociatedObject.Name,
                ObjectType = this.AssociatedObject.GetType().Name,
                MediaSource = this.Source,
                MediaTimeCode = this.AssociatedObject.Position,
            };

            this.Log(logEvent);
        }

        /// <summary>
        /// Log the DurationExtended event
        /// </summary>
        /// <param name="sender">the SmoothStreamingMediaElement</param>
        /// <param name="e">the duration extended event arguments</param>
        private void DurationExtended(object sender, DurationExtendedEventArgs e)
        {
            var logEvent = new AnalyticsEvent()
            {
                ActionValue = this.AssociatedObject.CurrentState.ToString(),
                EventArgs = this.CustomProperties,
                Name = "DurationExtended",
                ObjectName = this.AssociatedObject.Name,
                ObjectType = this.AssociatedObject.GetType().Name,
                MediaSource = this.Source,
                MediaTimeCode = this.AssociatedObject.Position,
                Value = System.Convert.ToInt32(e.Duration)
            };

            this.Log(logEvent);
        }

        /// <summary>
        /// Log the DownloadTrackChanged event
        /// </summary>
        /// <param name="sender">the SmoothStreamingMediaElement</param>
        /// <param name="e">the track changed event arguments</param>
        private void DownloadTrackChanged(object sender, TrackChangedEventArgs e)
        {
            var logEvent = new AnalyticsEvent()
            {
                ActionValue = this.AssociatedObject.CurrentState.ToString(),
                EventArgs = this.CustomProperties,
                Name = "DownloadTrackChanged",
                ObjectName = this.AssociatedObject.Name,
                ObjectType = this.AssociatedObject.GetType().Name,
                MediaSource = this.Source,
                MediaStreamType = e.StreamType,
                MediaTimeCode = this.AssociatedObject.Position,
                Track = new Microsoft.WebAnalytics.Data.TrackInfo()
                {
                    Bitrate = System.Convert.ToInt64(e.Track.Bitrate),
                    CustomAttributes = new Dictionary<string, string>(e.Track.CustomAttributes),
                    Index = e.Track.Index,
                    Language = e.Track.Language,
                    Name = e.Track.Name,
                    TrackData = new List<Microsoft.WebAnalytics.Data.TimelineEvent>(from timelineEvent in e.Track.TrackData
                                                                                    select new Microsoft.WebAnalytics.Data.TimelineEvent
                                                                                    {
                                                                                        EventTime = timelineEvent.EventTime
                                                                                    }),
                },
            };

            this.Log(logEvent);
        }

        /// <summary>
        /// Log the CurrentStateChanged event
        /// </summary>
        /// <param name="sender">the SmoothStreamingMediaElement</param>
        /// <param name="e">the routed event arguments</param>
        private void CurrentStateChanged(object sender, RoutedEventArgs e)
        {
            var logEvent = new AnalyticsEvent()
            {
                ActionValue = this.AssociatedObject.CurrentState.ToString(),
                EventArgs = this.CustomProperties,
                Name = "CurrentStateChanged",
                ObjectName = this.AssociatedObject.Name,
                ObjectType = this.AssociatedObject.GetType().Name,
                MediaSource = this.Source,
                MediaTimeCode = this.AssociatedObject.Position,
            };

            this.Log(logEvent);
        }

        /// <summary>
        /// Log the ClipStateChanged event
        /// </summary>
        /// <param name="sender">the SmoothStreamingMediaElement</param>
        /// <param name="e">the routed event arguments</param>
        private void ClipStateChanged(object sender, RoutedEventArgs e)
        {
            var logEvent = new AnalyticsEvent()
            {
                EventArgs = this.CustomProperties,
                Name = "ClipStateChanged",
                ObjectName = this.AssociatedObject.Name,
                ObjectType = this.AssociatedObject.GetType().Name,
                MediaSource = this.Source,
                MediaTimeCode = this.AssociatedObject.Position,
            };

            this.Log(logEvent);
        }

        /// <summary>
        /// Log the ClipError event
        /// </summary>
        /// <param name="sender">the SmoothStreamingMediaElement</param>
        /// <param name="e">the clip event arguments</param>
        private void ClipError(object sender, ClipEventArgs e)
        {
            var logEvent = new AnalyticsEvent()
            {
                EventArgs = this.CustomProperties,
                Clip = new Microsoft.WebAnalytics.Data.ClipContext()
                {
                    ClipInformation = new Microsoft.WebAnalytics.Data.ClipInformation()
                    {
                        ClickThroughUrl = e.Context.ClipInformation.ClickThroughUrl,
                        ClipUrl = e.Context.ClipInformation.ClipUrl,
                        Duration = e.Context.ClipInformation.Duration,
                        IsSmoothStreamingSource = e.Context.ClipInformation.IsSmoothStreamingSource
                    },
                    Data = e.Context.Data,
                    CurrentClipState = e.Context.CurrentClipState,
                    HasQuartileEvents = e.Context.HasQuartileEvents,
                },
                Name = "ClipError",
                ObjectName = this.AssociatedObject.Name,
                ObjectType = this.AssociatedObject.GetType().Name,
                MediaSource = this.Source,
                MediaTimeCode = this.AssociatedObject.Position,
            };

            this.Log(logEvent);
        }

        /// <summary>
        /// Log the ClipClickThrough event
        /// </summary>
        /// <param name="sender">the SmoothStreamingMediaElement</param>
        /// <param name="e">the clip event arguments</param>
        private void ClipClickThrough(object sender, ClipEventArgs e)
        {
            var logEvent = new AnalyticsEvent()
            {
                EventArgs = this.CustomProperties,
                Clip = new Microsoft.WebAnalytics.Data.ClipContext()
                {
                    ClipInformation = new Microsoft.WebAnalytics.Data.ClipInformation()
                    {
                        ClickThroughUrl = e.Context.ClipInformation.ClickThroughUrl,
                        ClipUrl = e.Context.ClipInformation.ClipUrl,
                        Duration = e.Context.ClipInformation.Duration,
                        IsSmoothStreamingSource = e.Context.ClipInformation.IsSmoothStreamingSource
                    },
                    Data = e.Context.Data,
                    CurrentClipState = e.Context.CurrentClipState,
                    HasQuartileEvents = e.Context.HasQuartileEvents,
                },
                MediaTimeCode = this.AssociatedObject.Position,
                Name = "ClipClickThrough",
                ObjectName = this.AssociatedObject.Name,
                ObjectType = this.AssociatedObject.GetType().Name,
                MediaSource = this.Source,
            };

            this.Log(logEvent);
        }

        /// <summary>
        /// Log the BufferingProgressChanged event
        /// </summary>
        /// <param name="sender">the SmoothStreamingMediaElement</param>
        /// <param name="e">the routed event arguments</param>
        private void BufferingProgressChanged(object sender, RoutedEventArgs e)
        {
            var logEvent = new AnalyticsEvent()
            {
                Name = "BufferingProgressChanged",
                ObjectName = this.AssociatedObject.Name,
                ObjectType = this.AssociatedObject.GetType().Name,
                MediaSource = this.Source,
                MediaTimeCode = this.AssociatedObject.Position,
                Value = System.Convert.ToInt32(this.AssociatedObject.BufferingProgress * 100)
            };

            this.Log(logEvent);
        }

        #endregion
    }
}
